import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router';
import store from '@/store';
import Login from '@/views/Login.vue'; // 登录组件
import Found404 from '@/components/404.vue'; // 404组件
import EmptyLayer from '@/components/EmptyLayer.vue';
import { Permission } from '@/types/interface/auth_interface';
import loadingDialog from '@/api/common/loading';

const routes: Array<RouteRecordRaw> = [
  {
    path: '/',
    redirect: 'login',
  },
  {
    path: '/login',
    name: 'login',
    component: Login,
  },
  {
    path: '/lesson',
    name: 'Lesson',
    component: () => import('@/views/page/tearchertack/mycourse/details/teachingdetails/classroom/lesson/Index.vue'),
  },
  {
    path: '/chatRoom',
    name: 'ChatRoom',
    component: () => import('@/views/page/tearchertack/mycourse/details/chatRoom/Index.vue'),
  },
  {
    path: '/backstage',
    name: 'backstage',
    component: () => import(/* webpackChunkName: "about" */ '@/views/Index.vue'),
    meta: {
      title: '主页',
    },
    children: [ // 使用 children 属性，实现子路由，同时，子路由的 path 前面，不要带 / ，否则永远以根路径开始请求，这样不方便我们用户去理解URL地址
      {
        path: '', // 默认子组件首页
        name: 'main',
        component: () => import(/* webpackChunkName: "about" */ '@/views/Main.vue'),
        meta: {
          title: '主界面',
        },
      },
      {
        path: 'user',
        // path: '/backstage/user',
        name: 'user',
        component: () => import('@/views/page/authority/user/Index.vue'),
        meta: {
          title: '个人用户',
        },
      },
      {
        path: 'details',
        name: 'details',
        component: () => import('@/views/page/tearchertack/mycourse/details/Index.vue'),
        meta: {
          title: '课程详情',
        },
      },
      {
        path: 'classmessage',
        name: 'classmessage',
        component: () => import('@/views/page/tearchertack/mycourse/details/teachingdetails/Index/Index.vue'),
        meta: {
          title: '课程信息',
        },
      },
      // {
      //   path: 'DepartmentManage',
      //   name: '部门管理',
      //   component: () => import('@/views/page/departmentmanage/Index.vue'),
      //   // beforeEnter() { window.location.href = 'http://www.baidu.com'; },
      // },
      // {
      //   path: 'MenuManage',
      //   name: '权限管理',
      //   component: () => import('@/views/page/permissionmanage/Index.vue'),
      // },
      // {
      //   path: 'RoleManage',
      //   name: '角色管理',
      //   component: () => import('@/views/page/rolemanage/Index.vue'),
      // },
      // {
      //   path: 'UserManage',
      //   name: '账户管理',
      //   component: () => import('@/views/page/usermanage/Index.vue'),
      // },
      {
        path: '404',
        name: '404',
        component: Found404,
      },
    ],
  },
  // { path: '/:catchAll(.*)', name: 'NotFound', redirect: '/backstage/404' }, // 如果要跳转的路由不存在，则跳转到404页面
];

const router = createRouter({
  // 用了history模式后,可以用两种方式操作：
  // 1.在服务器或本机测试时可以使用nginx服务来实现
  // 2.如果是单纯本机测试打包后的文件，可以在本机全局安装插件：npm install serve -g。然后用serve -s 【目录】来运行。例如本例http://localhost:3000
  history: createWebHistory(process.env.BASE_URL),
  routes,
});

// // 重置路由函数，用于切换用户时，或者退出时清除动态加载的路由
// const resetRouter = () => createRouter({
//   // 用了history模式后,可以用两种方式操作：
//   // 1.在服务器或本机测试时可以使用nginx服务来实现
//   // 2.如果是单纯本机测试打包后的文件，可以在本机全局安装插件：npm install serve -g。然后用serve -s 【目录】来运行。例如本例http://localhost:3000
//   history: createWebHistory(process.env.BASE_URL),
//   routes,
// });

// 定义一个路由对象，用于处理的路由路径不存在的情形。
// 如果要跳转的路由不存在，则跳转到404页面。因为该路由要放在最后，所以每次生成新的路由对象时都需要添加到最后
const NotFoundRoute = {
  path: '/:pathMatch(.*)',
  name: 'NotFound',
  redirect: '/backstage/404',
};

// 拼接生成路由数据，只对菜单对象进行生成
const createRoutesData = (permissions: Permission[], rootName?: string) => { // parentRouteName表示上级路由的name属性，用于插入子路由
  let parentRouteName = 'backstage'; // 默认的上级路由
  if (typeof rootName !== 'undefined') { // 如果传入上级路由的名字
    parentRouteName = rootName;
  }
  // 定义要添加的动态路由数组
  const routesNew = <RouteRecordRaw[]>[];
  // 遍历后端传递过来的权限信息，然后生成动态路由对象
  permissions.forEach((permission: Permission) => {
    if (permission.type === 1) { // 只对菜单对象生成路由
      let routeNew: RouteRecordRaw = {
        redirect: permission.redirect,
        path: permission.route,
        name: permission.component, //  自定义的容器名称，则用自定义的
        // name: permission.component ? permission.component : permission.name, //  如果没有自定义的容器名称，则用自定义的
        meta: {
          title: permission.name, // 路由的名称，用于导航路径
          requiresAuth: permission.requireAuth, // 是否要求登录后才能访问
          parentRouteName,
          // component: EmptyLayer,
        },
      };
      // 设置组件的component
      if (permission.path) { // 如果组件的路径存在
        // eslint-disable-next-line @typescript-eslint/ban-ts-comment
        // @ts-ignore
        routeNew.component = () => import(`@/views${permission.path}`); // 不能直接使用包含@或是@/符号的动态变量，因此这里要拆分
      } else { // 如果组件路径不存在。则有两种情况：1.正常情况是父容器，那么component不能为空；2.组件暂时未开发，只填写了路由的菜单
        if (permission.children) { // 如果还有子组件,说明是父组件。因为要放子组件进去，所以该组件设置为EmptyLayer组件（自定义）。否则会报错
          // eslint-disable-next-line @typescript-eslint/ban-ts-comment
          // @ts-ignore
          routeNew.component = EmptyLayer; // 不能直接使用包含@或是@/符号的动态变量，因此这里要拆分
        }
        // else { // 如果没有子组件，说明可能是没有组件地址的菜单（开发中）
        //   routeNew.redirect = '/backstage/404';
        //   // routeNew.component = Found404;
        // }
      }
      if (permission.url) { // 如果有连接地址，则让直接执行跳转
        routeNew.beforeEnter = () => {
          window.location.href = permission.url;
        };
      }
      routesNew.push(routeNew);
      if (permission.children && permission.children.length > 0) { // 如果还有子组件
        // 递归处理子路由的component
        routesNew.push(...createRoutesData(permission.children, permission.component));
      }
    }
  });
  return routesNew;
};

// 重置路由，主要用于用户注销或过期时的路由重置。
// 说明：因为router没有提供相关的重置方法，网上的方法在router4中又无效或是不符合eslint的规则（例如将router对象修改为let类型），刷新页面显得太row，因此选择手动删除
// 重置路由的要求：因为router.removeRoute是根据组件的name属性来删除的，因此后端必须为所有菜单都设置组件名称，且不应该重复。
const resetRouter = () => {
  // console.log('重置路由');
  // console.log('移除前');
  // console.log(router.getRoutes());
  // 获取拼接后的路由数据
  let data = createRoutesData(store.state.routes);
  // 删除原来动态添加的路由
  if (data && data.length > 0) { // 如果原来存储有路由信息
    // 遍历删除动态路由信息
    data.forEach((routeRaw: RouteRecordRaw) => {
      // console.log(`移除${String(routeRaw.name)}`);
      router.removeRoute(routeRaw.name!);
    });
  }
  // 手动删除路径不存在时的默认路由
  if (router.hasRoute(NotFoundRoute.name)) {
    router.removeRoute(NotFoundRoute.name);
  }
  // 注销本地存储的路由信息
  store.commit('clearRoutes');
  // store.dispatch('logout');
  // console.log('移除后');
  // console.log(router.getRoutes());
};

// 定义加载组建
const {
  startLoading,
  endLoading,
} = loadingDialog('正在组建菜单中，请稍后...');
// 对动态路由进行总处理，在每次路由跳转前触发
router.beforeEach(async (to, from) => {
  // console.log(router.getRoutes());
  if (from.path === '/login' && to.path !== '/login') { // 只有从登录界面跳转到其他界面，才会出现组建菜单的加载框
    startLoading();
  }
  store.commit('setRouteMatched', to.matched); // 将路由节点信息存入vuex，to.matched获取当前路由的每个路由节点的完整信息
  // 判断要跳转的路由是否原来已经存在。用于处理router官方文档中说明的中因跳转的权限是刚生成时，需要重定向路由的判定状态。
  const existRoute = router.hasRoute(to.name as string);
  if (to.path === '/login') { // 如果要跳转的登录页面，这种情况一般在手动注销或是超时在axios配置中被自动跳转到登录页面
    if (store.getters.getToken) { // 如果token还存在，说明不是直接从注销页面跳转，此时跳回登录后台首页。（业务设定）
      return '/backstage'; // 跳转到后台主界面
    } // 如果token已经不存在，说明已经注销或失效
    // 重置路由，移除所有登录用户的信息
    resetRouter();
  } else { // 如果是其他路径
    if (!store.getters.getToken) { // 如果token不存在，说明没有登录。直接在本地跳转
      return '/login'; // 跳到登录页面
    }
    // 如果已经登录
    if (!store.state.routes || store.state.routes.length === 0) { // 如果数组为空，说明该页面刚刚刷新
      // 重新在服务端加载路由信息
      await store.dispatch('getRoutes');
      // 获取拼接后的路由数据
      let data = createRoutesData(store.state.routes);
      // 动态添加路由
      data.forEach((routeRaw: RouteRecordRaw) => {
        // 添加在路由，为了考虑面包屑导航的路由能和菜单一致，要加上父容器子容器
        router.addRoute(routeRaw.meta!.parentRouteName!, routeRaw);
      });
      // 将404路由添加到最后
      router.addRoute(NotFoundRoute);
      // 打印组建完成后的动态路由
      // console.log(router.getRoutes());
      if (!existRoute) { // 如果要跳转的路由原来不存在，说明路由是本次动态添加的，此时重新定位一次，让刚添加的路由生效
        return to.fullPath;
      }
    }
  }
  // 关闭加载框
  endLoading();
  return true;
});

export default router;
